package com.permission.service;

import com.google.common.collect.Lists;
import com.permission.constant.AclStatusEnum;
import com.permission.constant.AclTypeEnum;
import com.permission.dao.SysAclMapper;
import com.permission.exception.AddException;
import com.permission.exception.DeleteException;
import com.permission.exception.ParamException;
import com.permission.exception.UpdateException;
import com.permission.model.SysAcl;
import com.permission.param.AddAclParam;
import com.permission.param.ReviseAclParam;
import com.permission.util.EnumUtil;
import com.permission.vo.SysAclVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Created by Administrator on 2018/4/15
 */
@Service
public class SysAclServiceImpl implements SysAclService {

    private static final int PARENT_ID = 0; // 数据库中顶级菜单默认的父ID，aclParentId = 0
    private static final String ACL_ID_NOT_EXIST = "权限ID不存在";
    private static final String PARENT_ID_NOT_EXIST = "父权限不存在";
    private static final String FAIL_TO_DELETE = "删除权限失败";
    private static final String FAIL_TO_REVISE = "修改权限失败";
    private static final String FAIL_TO_ADD = "增加权限失败";

    @Autowired
    private SysAclMapper sysAclMapper;

    private List<SysAclVo> assembleSysAclVoList(List<SysAcl> sysAclListAfterSort) {
        return sysAclListAfterSort.stream().map(
                    e -> {
                        SysAclVo sysAclVo = new SysAclVo();
                        BeanUtils.copyProperties(e, sysAclVo);
                        sysAclVo.setAclTypeDesc(Objects.requireNonNull(
                                EnumUtil.getByCode(sysAclVo.getAclType(), AclTypeEnum.class)).getMsg());
                        sysAclVo.setAclStatusDesc(Objects.requireNonNull(
                                EnumUtil.getByCode(sysAclVo.getAclStatus(), AclStatusEnum.class)).getMsg());
                        return sysAclVo;
                    }
            ).collect(Collectors.toList());
    }

    private List<Integer> getAllAclIds(Integer aclId) {
        List<Integer> result = Lists.newArrayList();
        List<Integer> in = Lists.newArrayList();
        in.add(aclId);

        SysAcl sysAcl = getSysAcl(aclId, ACL_ID_NOT_EXIST);
        result.add(sysAcl.getAclId());

        result = findChildAclIds(result, in);
        return result;
    }

    private SysAcl getSysAcl(Integer aclId, String aclIdNotExist) {
        SysAcl sysAcl = sysAclMapper.selectByPrimaryKey(aclId);
        if (sysAcl == null) {
            throw new ParamException(aclIdNotExist);
        }
        return sysAcl;
    }

    private List<Integer> findChildAclIds(List<Integer> out, List<Integer> in) {
        for (Integer aclId : in) {
            List<Integer> result = sysAclMapper.selectAclIdByAclParentId(aclId);
            if (result != null) {
                out.addAll(result);
                out = findChildAclIds(out, result);
            }
        }
        return out;
    }

    private List<SysAcl> order(List<SysAcl> in) {
        List<SysAcl> sysAclList = Lists.newArrayList();
        sysAclList = findChild(sysAclList, in, PARENT_ID);
        return sysAclList;
    }

    private List<SysAcl> findChild(List<SysAcl> out, List<SysAcl> in, Integer parentId) {
        for (SysAcl sysAcl : in ) {
            if (sysAcl.getAclParentId().equals(parentId)) {
                out.add(sysAcl);
                out = findChild(out, in, sysAcl.getAclId());
            }
        }

        return out;
    }

    private Integer checkParentAndGetLevel(Integer parentId){
        Integer level = 1;
        // 如果父ID不为0，检查父权限是否存在
        if (!parentId.equals(PARENT_ID)) {
            SysAcl parent = getSysAcl(parentId, PARENT_ID_NOT_EXIST);
            // 计算level
            level = parent.getAclLevel() + 1;
        }

        return level;
    }

    /**
     * 查询所有权限
     *
     * @return List<SysAclVo>
     */
    @Override
    public List<SysAclVo> all() {
        List<SysAcl> sysAclListAfterSort = order(sysAclMapper.selectAll());
        return assembleSysAclVoList(sysAclListAfterSort);
    }

    /**
     * 增加权限
     *
     * @param addAclParam addAclParam
     */
    @Override
    public void add(AddAclParam addAclParam) {
        Integer level = checkParentAndGetLevel(addAclParam.getAclParentId());
        SysAcl sysAcl = new SysAcl();
        BeanUtils.copyProperties(addAclParam, sysAcl);
        sysAcl.setAclLevel(level);
        int result = sysAclMapper.insertSelective(sysAcl);
        if (result != 1) {
            throw new AddException(FAIL_TO_ADD);
        }
    }

    /**
     * 修改权限
     *
     * @param reviseAclParam reviseAclParam
     */
    @Override
    public void update(ReviseAclParam reviseAclParam) {
        Integer level = checkParentAndGetLevel(reviseAclParam.getAclParentId());
        SysAcl sysAcl = new SysAcl();
        BeanUtils.copyProperties(reviseAclParam, sysAcl);
        sysAcl.setAclLevel(level);
        int result = sysAclMapper.updateByPrimaryKeySelective(sysAcl);
        if (result != 1) {
            throw new UpdateException(FAIL_TO_REVISE);
        }
    }

    /**
     * 删除权限
     *
     * @param aclId aclId
     * @return int
     */
    @Override
    public int delete(Integer aclId) {
        List<Integer> aclIdList = getAllAclIds(aclId);
        if (aclIdList == null || aclIdList.isEmpty()) {
            throw new ParamException(ACL_ID_NOT_EXIST);
        }

        int result = sysAclMapper.deleteByAclIdList(aclIdList);
        if (result <= 0) {
            throw new DeleteException(FAIL_TO_DELETE);
        }

        return result;
    }
}
